package cn.sc.summer.constant.util;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.sc.summer.constant.enums.WeekDayEnum;
import cn.sc.summer.constant.model.DateOverlapsCheck;
import cn.sc.summer.constant.model.TimeOverlapsCheck;
import cn.sc.summer.constant.project.DateConstant;
import org.springframework.lang.NonNull;

import java.sql.Time;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * 类名：时间类工具
 *
 * @author a-xin
 * @date 16:38
 */
public class DateUtilX extends DateUtil {

    /**
     * 接口:string类型日期转换
     *
     * @param time      需要转换的日期时间
     * @param oldFormat 需要转换的日期格式
     * @param newFormat 需要转换成的日期格式
     * @return java.lang.String 转换后日期字符串
     * @author a-xin
     * @date 2023/3/7 5:28 PM
     */
    public static String dateFormat(String time, String oldFormat, String newFormat) {
        return DateUtil.format(DateUtil.parse(time, oldFormat), newFormat);
    }

    /**
     * 接口:获取当前时间是星期几
     *
     * @param time   需要获取的时间
     * @param format 需要转化时间格式
     * @return java.lang.String 指定日期的星期几
     * @author a-xin
     * @date 2023/3/30 19:39
     */
    public static String getWeek(String time, String format) {
        DateTime parse = DateUtil.parse(time, format);
        return getWeek(parse);
    }

    /**
     * 接口:获取当前时间是星期几
     *
     * @param date 需要获取的时间
     * @return java.lang.String 指定日期的星期几
     * @author a-xin
     * @date 2023/3/30 19:39
     */
    public static String getWeek(Date date) {
        int sort = DateUtil.dayOfWeek(date);
        return WeekDayEnum.getByNational(sort);
    }

    /**
     * 接口: 获取两个日期之间的日期
     *
     * @param startDate 开始日期
     * @param endDate   结束日期
     * @param format    传入，返回的日期格式
     * @return java.util.List<java.lang.String> 指定日期之间的日期集合
     * @author a-xin
     * @date 2023/5/11 10:23
     */
    public static List<String> getDaysBetween(String startDate, String endDate, String format) {
        List<String> dateList = new ArrayList<>();
        try {
            Date dateOne = DateUtil.parse(startDate, format);
            Date dateTwo = DateUtil.parse(endDate, format);
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(dateOne);
            dateList.add(startDate);
            while (dateTwo.after(calendar.getTime())) {
                calendar.add(Calendar.DAY_OF_MONTH, 1);
                dateList.add(DateUtil.format(calendar.getTime(), format));
            }
        } catch (Exception e) {
            throw new RuntimeException("Time conversion exception！");
        }
        return dateList;
    }

    /**
     * 接口: 获取两个日期之间的日期
     *
     * @param startDate 开始日期
     * @param endDate   结束日期
     * @param format    传入，返回的日期格式
     * @return java.util.List<java.lang.String> 指定日期之间的日期集合
     * @author a-xin
     * @date 2023/5/11 10:23
     */
    public static List<String> getDaysBetween(Date startDate, Date endDate, String format) {
        List<String> dateList = new ArrayList<>();
        try {
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(startDate);
            dateList.add(DateUtil.format(startDate, format));
            while (endDate.after(calendar.getTime())) {
                calendar.add(Calendar.DAY_OF_MONTH, 1);
                dateList.add(DateUtil.format(calendar.getTime(), format));
            }
        } catch (Exception e) {
            throw new RuntimeException("Time conversion exception！");
        }
        return dateList;
    }

    /**
     * 接口: 获取两个日期之间的日期
     *
     * @param startDate 开始日期
     * @param endDate   结束日期
     * @return java.util.List<java.lang.String> 指定日期之间的日期集合
     * @author a-xin
     * @date 2023/5/11 10:23
     */
    public static List<Date> getDaysBetween(Date startDate, Date endDate) {
        List<Date> dateList = new ArrayList<>();
        try {
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(startDate);
            dateList.add(startDate);
            while (endDate.after(calendar.getTime())) {
                calendar.add(Calendar.DAY_OF_MONTH, 1);
                dateList.add(calendar.getTime());
            }
        } catch (Exception e) {
            throw new RuntimeException("Time conversion exception！");
        }
        return dateList;
    }

    /**
     * 接口: 获取两个日期之间的日期
     *
     * @param startDate 开始日期
     * @param endDate   结束日期
     * @param format    传入，返回的日期格式
     * @return java.util.List<java.lang.String> 指定日期之间的日期集合
     * @author a-xin
     * @date 2023/5/11 10:23
     */
    public static List<String> getMonthsBetween(String startDate, String endDate, String format) {
        List<String> dateList = new ArrayList<>();
        try {
            Date dateOne = DateUtil.parse(startDate, format);
            Date dateTwo = DateUtil.parse(endDate, format);
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(dateOne);
            dateList.add(startDate);
            while (dateTwo.after(calendar.getTime())) {
                calendar.add(Calendar.MONTH, 1);
                dateList.add(DateUtil.format(calendar.getTime(), format));
            }
        } catch (Exception e) {
            throw new RuntimeException("Time conversion exception！");
        }
        return dateList;
    }

    /**
     * 接口: 获取两个日期之间的日期
     *
     * @param startDate 开始日期
     * @param endDate   结束日期
     * @param format    传入，返回的日期格式
     * @return java.util.List<java.lang.String> 指定日期之间的日期集合
     * @author a-xin
     * @date 2023/5/11 10:23
     */
    public static List<String> getMonthsBetween(Date startDate, Date endDate, String format) {
        List<String> dateList = new ArrayList<>();
        try {
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(startDate);
            dateList.add(DateUtil.format(startDate, format));
            while (endDate.after(calendar.getTime())) {
                calendar.add(Calendar.MONTH, 1);
                dateList.add(DateUtil.format(calendar.getTime(), format));
            }
        } catch (Exception e) {
            throw new RuntimeException("Time conversion exception！");
        }
        return dateList;
    }

    /**
     * 接口: 获取两个月份之间的月份
     *
     * @param startDate 开始日期
     * @param endDate   结束日期
     * @return java.util.List<java.lang.String> 指定日期之间的日期集合
     * @author a-xin
     * @date 2023/5/11 10:23
     */
    public static List<Date> getMonthsBetween(Date startDate, Date endDate) {
        List<Date> dateList = new ArrayList<>();
        try {
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(startDate);
            dateList.add(startDate);
            while (endDate.after(calendar.getTime())) {
                calendar.add(Calendar.MONTH, 1);
                dateList.add(calendar.getTime());
            }
        } catch (Exception e) {
            throw new RuntimeException("Time conversion exception！");
        }
        return dateList;
    }

    /**
     * 接口: 获取当前时间到明日00:00:00的时间值-单位：毫秒
     *
     * @return java.lang.Long 间隔时间值
     * @author a-xin
     * @date 2023/8/1 15:43
     */
    public static Long getLongTimeToTomorrow() {
        DateTime tomorrowDate = DateUtil.offsetDay(new Date(), 1);
        String tomorrowDateFormat = DateUtil.format(tomorrowDate, DateConstant.YY_MM_DD_3);
        DateTime tomorrowDateTime = DateUtil.parse(tomorrowDateFormat + DateConstant.TIME_ZERO, DateConstant.YYYY_MM_DD_HH_MM_SS_3);
        return tomorrowDateTime.getTime() - System.currentTimeMillis();
    }

    /**
     * 校验格式是否为指定的日期格式
     *
     * @param checkStr 需要校验字符串
     * @param format   日期格式
     * @return 是否正确格式
     */
    public static Boolean checkFormat(String checkStr, String format) {
        try {
            DateUtil.parse(checkStr, format);
            return Boolean.TRUE;
        } catch (Exception e) {
            return Boolean.FALSE;
        }
    }

    /**
     * 获取指定时间区间内命中的天数（例如：周一，周二）
     *
     * @param startDate 开始时间，只针对于天
     * @param endDate   结束时间，只针对于天
     * @param hitConfig 命中星期配置{@link WeekDayEnum}
     * @return 命中的时间日期
     */
    public static List<Date> getDateHit(Date startDate, Date endDate, List<Integer> hitConfig) {
        List<Date> daysBetween = DateUtilX.getDaysBetween(startDate, endDate);
        return daysBetween.stream().filter(day -> {
            int sort = DateUtilX.dayOfWeek(day);
            return hitConfig.contains(sort);
        }).collect(Collectors.toList());
    }

    /**
     * 校验格式是否为指定的日期格式
     *
     * @param checkStr 需要校验字符串
     * @param format   日期格式
     * @return 是否正确格式
     */
    public static Boolean checkFormat(Collection<String> checkStr, String format) {
        AtomicReference<Boolean> flag = new AtomicReference<>(Boolean.TRUE);
        checkStr.stream().forEach(item -> {
            try {
                DateUtil.parse(item, format);
            } catch (Exception e) {
                flag.set(Boolean.FALSE);
            }
        });
        return flag.get();
    }

    /**
     * 校验多个时间段是否有重合
     *
     * @param dateOverlapsChecks 时间段
     * @return 是否重合，true为有重合
     */
    public static Boolean checkDateOverlaps(@NonNull List<DateOverlapsCheck> dateOverlapsChecks) {
        for (int i = 0; i < dateOverlapsChecks.size(); i++) {
            DateOverlapsCheck date1 = dateOverlapsChecks.get(i);
            Date endTime = date1.getEndTime();
            for (int j = 0; j < dateOverlapsChecks.size(); j++) {
                if (i != j) {
                    DateOverlapsCheck date2 = dateOverlapsChecks.get(j);
                    Date startTime1 = date2.getStartTime();
                    if (startTime1.before(endTime)) {
                        return Boolean.TRUE;
                    }
                }
            }
        }
        return Boolean.FALSE;
    }

    /**
     * 校验多个时间段是否有重合
     *
     * @param timeOverlapsChecks 时间段
     * @return 是否重合，true为有重合
     */
    public static Boolean checkTimeOverlaps(@NonNull List<TimeOverlapsCheck> timeOverlapsChecks) {
        for (int i = 0; i < timeOverlapsChecks.size(); i++) {
            TimeOverlapsCheck time1 = timeOverlapsChecks.get(i);
            Time endTime = time1.getEndTime();
            for (int j = 0; j < timeOverlapsChecks.size(); j++) {
                if (i != j) {
                    TimeOverlapsCheck time2 = timeOverlapsChecks.get(j);
                    Time startTime1 = time2.getStartTime();
                    if (startTime1.before(endTime)) {
                        return Boolean.TRUE;
                    }
                }
            }
        }
        return Boolean.FALSE;
    }

    /**
     * 日期批量格式化
     *
     * @param dateList 日期集合
     * @param format   格式化表达式
     * @return 格式化后时间
     */
    public static List<String> formatBatch(Collection<Date> dateList, String format) {
        return dateList.stream().map(date -> DateUtil.format(date, format)).collect(Collectors.toList());
    }

    /**
     * 字符串批量转换成日期
     *
     * @param dateStr 日期字符串
     * @param format  日期格式
     * @return 格式化后时间信息
     */
    public static List<Date> parseBatch(Collection<String> dateStr, String format) {
        return dateStr.stream().map(date -> DateUtil.parse(date, format)).collect(Collectors.toList());
    }

}
